package com.sxpcwlkj.common.utils;


import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import com.sxpcwlkj.common.code.entity.PrivateKeyEntity;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;

import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;

/**
 * 非对称 加密 解密
 * AES加密php,java,.net三种语言同步实现加密、解密
 * 其他语言文档: https://blog.sxpcwlkj.com/articles/168
 *
 * @name: EncryptionUtil
 * @author: 西决
 * @date: 2022/12/01
 **/

public class EncryptionUtils {



    //====================== 公共方法 ==========================

    /**
     * 字节数组转成16进制字符串
     *
     * @param b 一个字节的数
     * @return
     */
    public static String byte2hex(byte[] b) {
        StringBuffer sb = new StringBuffer(b.length * 2);
        String tmp;
        for (int n = 0; n < b.length; n++) {
            // 整数转成十六进制表示
            tmp = (Integer.toHexString(b[n] & 0XFF));
            if (tmp.length() == 1) {
                sb.append("0");
            }
            sb.append(tmp);
        }
        return sb.toString().toUpperCase(); // 转成大写
    }

    /**
     * 将hex字符串转换成字节数组
     *
     * @param inputString
     * @return
     */
    private static byte[] hex2byte(String inputString) {
        if (inputString == null || inputString.length() < 2) {
            return new byte[0];
        }
        inputString = inputString.toLowerCase();
        int l = inputString.length() / 2;
        byte[] result = new byte[l];
        for (int i = 0; i < l; ++i) {
            String tmp = inputString.substring(2 * i, 2 * i + 2);
            result[i] = (byte) (Integer.parseInt(tmp, 16) & 0xFF);
        }
        return result;
    }

    //====================AES对称性加密解密=========================

    /**
     * AES加密php,java,.net三种语言同步实现加密、解密
     * 其他语言文档: https://blog.sxpcwlkj.com/articles/168
     * 生成一个AES密钥字符串
     * PS：对称性加密和解密用同一个 秘钥
     *
     * @return
     */
    public static String getAesKey() {
        try {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");
            kgen.init(128, new SecureRandom());
            SecretKey secretKey = kgen.generateKey();
            byte[] enCodeFormat = secretKey.getEncoded();
            SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
            if (key == null) return null;
            return byte2hex(key.getEncoded());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * AES加密php,java,.net三种语言同步实现加密、解密
     * 其他语言文档: https://blog.sxpcwlkj.com/articles/168
     * 通过String类型的密钥加密String
     *
     * @param content
     * @param key
     * @return 16进制密文字符串
     */
    public static String encryptAes(String content, String key) {
        try {
            //构建
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            // 字符串装Byte
            byte[] byteKey = new SecretKeySpec(hex2byte(key), "AES").getEncoded();
            //初始化
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(byteKey, "AES"));
            // 字符串转byte加密，返回byte字节
            byte[] data = cipher.doFinal(content.getBytes("UTF-8"));
            String result = byte2hex(data);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 通过String类型的密钥 解密String类型的密文
     *
     * @param content
     * @param key
     * @return
     */
    public static String decryptAes(String content, String key) {
        byte[] data = null;
        try {
            //构建
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            //初始化
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(hex2byte(key), "AES"));
            //解密
            data = cipher.doFinal(hex2byte(content));
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (data == null) return null;
        String result = null;
        try {
            result = new String(data, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }


    //====================== 扩展RSA非对称加密 ==========================

    /**
     * 随机生成一对非对称加密 公钥与私钥
     *
     * @return
     */
    public static PrivateKeyEntity getRsaKey() {

        Map<String, Object> rsaMap = new HashMap<String, Object>();
        RSA rsa = new RSA();
        //获得私钥
        rsaMap.put("privateKey", rsa.getPrivateKeyBase64());
        //获得公钥
        rsaMap.put("publicKey", rsa.getPublicKeyBase64());

        return new PrivateKeyEntity(rsa.getPublicKeyBase64(), rsa.getPrivateKeyBase64());
    }

    /**
     * 公钥加密
     *
     * @param content      报文字符串
     * @param publicKeyStr 公钥
     * @return
     */
    public static String encryptRsa(String content, String publicKeyStr) {
        RSA rsa = new RSA(null, publicKeyStr);
        byte[] encrypt = rsa.encrypt(StrUtil.bytes(content, CharsetUtil.CHARSET_UTF_8), KeyType.PublicKey);
        return byte2hex(encrypt);
    }

    /**
     * 私钥解密
     *
     * @param encrypt       加密字符串
     * @param privateKeyStr 私钥
     * @return
     */
    public static String decryptRsa(String encrypt, String privateKeyStr) {
        RSA rsa = new RSA(privateKeyStr, null);
        byte[] decrypt = rsa.decrypt(encrypt, KeyType.PrivateKey);
        return StrUtil.str(decrypt, CharsetUtil.CHARSET_UTF_8);
    }

    /**
     * 解密数据库密码
     * @param privateKey
     * @param userPassword
     * @return
     */
    public static String getPassword( String userPassword,String privateKey) {
        return EncryptionUtils.decryptRsa(userPassword, privateKey);
    }


    public static void main(String[] args) {
        try {

            // 内容
            String content = "123456";

            // 生成AES密钥
            String aesKey = EncryptionUtils.getAesKey();
            System.out.println("AES-KEY:" + aesKey);
            // 用AES加密内容
            String aesMiContent = EncryptionUtils.encryptAes(content, aesKey);
            System.out.println("AES加密后的内容:" + aesMiContent);
            // 用AES解密内容
            String aesMingContent = EncryptionUtils.decryptAes(aesMiContent, aesKey);
            System.out.println("AES解密后的内容:" + aesMingContent);

            System.out.println("=========================================");

            // 生成RSA密钥对
            PrivateKeyEntity rsaKey = EncryptionUtils.getRsaKey();

            System.out.println("RSA-KEY:" + rsaKey.toString());
            // 用AES加密内容
            String rsaMiContent = EncryptionUtils.encryptRsa(content, rsaKey.getPublicKey());
            System.out.println("RSA加密后的内容:" + rsaMiContent);
            // 用AES解密内容
            String rsaMingContent = EncryptionUtils.decryptRsa(rsaMiContent, rsaKey.getPrivateKey());
            System.out.println("RSA解密后的内容:" + rsaMingContent);

            String password="8861B3C54DBA1EAA2A0592D0A15DB0F788610E1AFA066B07A271E04371E573E6196A3423C74B3564FCBD3C59E6758EE6367EE82E11367000D65EEF53FC38B41D36FB3735EDFE24EF92EC36DF3A8B0D6669094445BDB7FAEF0ED3A497915243B6E95DBA805FF040366240AA35043E85DD5BD58821DCD679EFF92450E58FC446C8";
            String md5 = SecureUtil.md5(password);

            System.out.println(md5);

        } catch (Exception e) {
            e.printStackTrace();
            // TODO: handle exception
        }

    }

}
